package com.cinyi.cyds.base.redis;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.cinyi.cyds.util.ConfigUtil;

import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisShardInfo;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPool;
import redis.clients.jedis.exceptions.JedisException;

/**
 * redis数据库操作对象
 * @author penghui
 *
 */
public class RedisHelper {

	private static final Logger log = LoggerFactory.getLogger(RedisHelper.class);

	private ShardedJedisPool pool = null;
	private ShardedJedis shardedJedis = null;
	private boolean enabled = false;

	protected RedisHelper() {
		initialPool();
	}

	private void initialPool() {
		try {
			JedisPoolConfig config = new JedisPoolConfig();
			config.setMaxTotal(ConfigUtil.getInt("redis.pool.maxTotal", 200));
			config.setMaxIdle(ConfigUtil.getInt("redis.pool.maxIdle",20));
			config.setTimeBetweenEvictionRunsMillis(ConfigUtil.getLongProperty(
					"redis.pool.timeBetweenEvictionRunsMillis", 30000L));
			config.setMinEvictableIdleTimeMillis(ConfigUtil.getInt(
					"redis.pool.minEvictableIdleTimeMillis", 30000));
			config.setTestOnBorrow(ConfigUtil.getBooleanProperty(
					"redis.pool.testOnBorrow", true));
			config.setTestOnReturn(ConfigUtil.getBooleanProperty(
					"redis.pool.testOnReturn", true));
			config.setMaxWaitMillis(ConfigUtil.getLongProperty("redis.maxwait", 30000L)) ;
			
			String host = ConfigUtil.get("redis.pool.host","redis-server:6379");
			List<JedisShardInfo> list = new ArrayList<JedisShardInfo>();
			String[] addressArr = host.split(",");
			for (String str : addressArr) {
				list.add(new JedisShardInfo(str.split(":")[0], Integer
						.parseInt(str.split(":")[1])));
			}
			pool = new ShardedJedisPool(config, list);
			enabled = true;
		} catch (JedisException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * 获得jedis客户端
	 * 
	 * @return
	 */
	public synchronized ShardedJedis getJedisClient() {
		if (pool == null) {
			initialPool();
		}

		// double check
		if (pool == null) {
			log.error("getJedisInstance-no-instance");
			return null;
		}

		try {
			return pool.getResource();
		} catch (Exception e) {
			log.error("getJedisInstance-failed", e);
			return null;
		}
	}

	/**
	 * 关闭 Redis
	 */
	public void destory() {
		pool.destroy();
	}

	/**
	 * redis的List集合 ，向key这个list添加元素
	 * 
	 * @param key
	 *            List别名
	 * @param string
	 *            元素
	 * @return
	 */
	public long rpush(String key, String string) {
		try {
			shardedJedis = getJedisClient();
			long ret = shardedJedis.rpush(key, string);
			pool.returnResource(shardedJedis);
			return ret;
		} catch (Exception e) {
			log.error(e.getMessage());
			throw new JedisException(e);
		} finally {
			if (shardedJedis != null) {
				pool.returnBrokenResource(shardedJedis);
			}
		}
	}

	/**
	 * 获取key这个List，从第几个元素到第几个元素 LRANGE key start
	 * stop返回列表key中指定区间内的元素，区间以偏移量start和stop指定。
	 * 下标(index)参数start和stop都以0为底，也就是说，以0表示列表的第一个元素，以1表示列表的第二个元素，以此类推。
	 * 也可以使用负数下标，以-1表示列表的最后一个元素，-2表示列表的倒数第二个元素，以此类推。
	 * 
	 * @param key
	 *            List别名
	 * @param start
	 *            开始下标
	 * @param end
	 *            结束下标
	 * @return
	 */
	public List<String> lrange(String key, long start, long end) {
		try {
			shardedJedis = getJedisClient();
			List<String> ret = shardedJedis.lrange(key, start, end);
			pool.returnResource(shardedJedis);
			return ret;
		} catch (Exception e) {
			log.error(e.getMessage());
			throw new JedisException(e);
		} finally {
			if (shardedJedis != null) {
				pool.returnBrokenResource(shardedJedis);
			}
		}
	}

	/**
	 * 将哈希表key中的域field的值设为value。
	 * 
	 * @param key
	 *            哈希表别名
	 * @param field键
	 * @param value
	 *            值
	 */
	public void hset(String key, String field, String value) {
		try {
			shardedJedis = getJedisClient();
			shardedJedis.hset(key, field, value);
			pool.returnResource(shardedJedis);
		} catch (Exception e) {
			log.error(e.getMessage());
			throw new JedisException(e);
		} finally {
			if (shardedJedis != null) {
				pool.returnBrokenResource(shardedJedis);
			}
		}
	}

	/**
	 * 向key赋值
	 * 
	 * @param key
	 * @param value
	 */
	public synchronized void set(String key, String value) {
		try {
			shardedJedis = getJedisClient();
			shardedJedis.set(key, value);
		} catch (Exception e) {
			e.printStackTrace();
			log.error(e.getMessage());
			throw new JedisException(e);
		} finally {
			if (shardedJedis != null) {
				pool.returnResource(shardedJedis);
			}
		}
	}

	/**
	 * 获取key的值
	 * 
	 * @param key
	 * @return
	 */
	public synchronized String get(String key) throws JedisException {
		try {
			shardedJedis = getJedisClient();
			return shardedJedis.get(key);
		} catch (Exception e) {
			log.error(e.getMessage());
			throw new JedisException(e);
		} finally {
			if (shardedJedis != null)
				pool.returnResource(shardedJedis);
		}
	}

	public synchronized String getSet(String key,String value) throws JedisException {
		try {
			shardedJedis = getJedisClient();
			return shardedJedis.getSet(key, value);
		} catch (Exception e) {
			log.error(e.getMessage());
			throw new JedisException(e);
		} finally {
			if (shardedJedis != null)
				pool.returnResource(shardedJedis);
		}
	}

	
	/**
	 * 将多个field - value(域-值)对设置到哈希表key中。
	 * 
	 * @param key
	 * @param map
	 */
	public void hmset(String key, Map<String, String> map) {
		try {
			shardedJedis = getJedisClient();
			shardedJedis.hmset(key, map);
			pool.returnResource(shardedJedis);
		} catch (Exception e) {
			log.error(e.getMessage());

			throw new JedisException(e);
		} finally {
			if (shardedJedis != null) {
				pool.returnBrokenResource(shardedJedis);
			}
		}
	}

	/**
	 * 给key赋值，并生命周期设置为seconds
	 * 
	 * @param key
	 * @param seconds
	 *            生命周期 秒为单位
	 * @param value
	 */
	public void setex(String key, int seconds, String value) {
		try {
			shardedJedis = getJedisClient();
			shardedJedis.setex(key, seconds, value);
			pool.returnResource(shardedJedis);
		} catch (Exception e) {
			log.error(e.getMessage());

			throw new JedisException(e);
		} finally {
			if (shardedJedis != null) {
				pool.returnBrokenResource(shardedJedis);
			}
		}
	}

	/**
	 * 为给定key设置生命周期
	 * 
	 * @param key
	 * @param seconds
	 *            生命周期 秒为单位
	 */
	public void expire(String key, int seconds) {
		try {
			shardedJedis = getJedisClient();
			shardedJedis.expire(key, seconds);
			pool.returnResource(shardedJedis);
		} catch (Exception e) {
			log.error(e.getMessage());
			throw new JedisException(e);
		} finally {
			if (shardedJedis != null) {
				pool.returnBrokenResource(shardedJedis);
			}
		}
	}

	/**
	 * 检查key是否存在
	 * 
	 * @param key
	 * @return
	 */
	public boolean exists(String key) {
		try {
			shardedJedis = getJedisClient();
			boolean bool = shardedJedis.exists(key);
			pool.returnResource(shardedJedis);
			return bool;
		} catch (Exception e) {
			log.error(e.getMessage());

			throw new JedisException(e);
		} finally {
			if (shardedJedis != null) {
				pool.returnBrokenResource(shardedJedis);
			}
		}
	}

	/**
	 * 返回key值的类型 none(key不存在),string(字符串),list(列表),set(集合),zset(有序集),hash(哈希表)
	 * 
	 * @param key
	 * @return
	 */
	public String type(String key) {
		try {
			shardedJedis = getJedisClient();
			String type = shardedJedis.type(key);
			pool.returnResource(shardedJedis);
			return type;
		} catch (Exception e) {
			log.error(e.getMessage());
			throw new JedisException(e);
		} finally {
			if (shardedJedis != null) {
				pool.returnBrokenResource(shardedJedis);
			}
		}
	}

	/**
	 * 从哈希表key中获取field的value
	 * 
	 * @param key
	 * @param field
	 */
	public String hget(String key, String field) {
		try {
			shardedJedis = getJedisClient();
			String value = shardedJedis.hget(key, field);
			pool.returnResource(shardedJedis);
			return value;
		} catch (Exception e) {
			log.error(e.getMessage());
			throw new JedisException(e);
		} finally {
			if (shardedJedis != null) {
				pool.returnBrokenResource(shardedJedis);
			}
		}
	}

	/**
	 * 返回哈希表key中，所有的域和值
	 * 
	 * @param key
	 * @return
	 */
	public Map<String, String> hgetAll(String key) {
		try {
			shardedJedis = getJedisClient();
			Map<String, String> map = shardedJedis.hgetAll(key);
			pool.returnResource(shardedJedis);
			return map;
		} catch (Exception e) {
			log.error(e.getMessage());
			throw new JedisException(e);
		} finally {
			if (shardedJedis != null) {
				pool.returnBrokenResource(shardedJedis);
			}
		}

	}

	/**
	 * 返回哈希表key中，所有的域和值
	 * 
	 * @param key
	 * @return
	 */
	public Set<?> smembers(String key) {
		try {
			shardedJedis = getJedisClient();
			Set<?> set = shardedJedis.smembers(key);
			pool.returnResource(shardedJedis);
			return set;
		} catch (Exception e) {
			log.error(e.getMessage());
			throw new JedisException(e);
		} finally {
			if (shardedJedis != null) {
				pool.returnBrokenResource(shardedJedis);
			}
		}
	}

	/**
	 * 移除集合中的member元素
	 * 
	 * @param key
	 *            List别名
	 * @param field
	 *            键
	 */
	public void delSetObj(String key, String field) {
		try {
			shardedJedis = getJedisClient();
			shardedJedis.srem(key, field);
			pool.returnResource(shardedJedis);
		} catch (Exception e) {
			log.error(e.getMessage());
			throw new JedisException(e);
		} finally {
			if (shardedJedis != null) {
				pool.returnBrokenResource(shardedJedis);
			}
		}
	}

	public synchronized void del(String key) {
		try {
			shardedJedis = getJedisClient();
			shardedJedis.del(key);
		} catch (Exception e) {
			log.error(e.getMessage());
			throw new JedisException(e);
		} finally {
			if (shardedJedis != null)
				pool.returnResource(shardedJedis);
		}
	}

	/**
	 * 判断member元素是否是集合key的成员。是（true），否则（false）
	 * 
	 * @param key
	 * @param field
	 * @return
	 */
	public boolean isNotField(String key, String field) {
		try {
			shardedJedis = getJedisClient();
			boolean bool = shardedJedis.sismember(key, field);
			pool.returnResource(shardedJedis);
			return bool;
		} catch (Exception e) {
			log.error(e.getMessage());
			throw new JedisException(e);
		} finally {
			if (shardedJedis != null) {
				pool.returnBrokenResource(shardedJedis);
			}
		}
	}

	/**
	 * 如果key已经存在并且是一个字符串，将value追加到key原来的值之后
	 * 
	 * @param key
	 * @param value
	 */
	public void append(String key, String value) {
		try {
			shardedJedis = getJedisClient();
			shardedJedis.append(key, value);
			pool.returnResource(shardedJedis);
		} catch (Exception e) {
			log.error(e.getMessage());
			throw new JedisException(e);
		} finally {
			if (shardedJedis != null) {
				pool.returnBrokenResource(shardedJedis);
			}
		}
	}

	public boolean isEnabled() {
		return enabled;
	}

	public static void main(String[] args) {
		RedisHelper redis = new RedisHelper();
		for (int i = 0; i < 2; i++) {
			redis.set("a" + i, "test-" + i);
		}

		redis.destory();
	}

}
